/*
 * Copyright (C) 2019-2020 Alibaba Group Holding Limited
 */

#include "genie_sal.h"
#include "genie_mesh_api.h"

#include "sensor_led.h"
#include "sensor_queue.h"
#include "sensor.h"

static sensor_led_t led;

int32_t sensor_set_led_status(led_status_e staus)
{
    int32_t ret = 0;

    if (staus == LED_ON)
    {
        ret = hal_gpio_output_low(&led.led_gpio);
    }
    else
    {
        ret = hal_gpio_output_high(&led.led_gpio);
    }

    if (ret != 0)
    {
        GENIE_LOG_ERR("fail ret:%d", ret);
    }

    return ret;
}

static void led_timer_cb(void *timer, void *arg)
{
    if (--led.blink_count > 0)
    {
        hal_gpio_output_toggle(&led.led_gpio);
    }
    else
    {
        aos_timer_stop(&led.blink_timer);
        sensor_set_led_status(LED_OFF);
    }
}

static void delay_sleep_timer_cb(void *timer, void *arg)
{
    queue_mesg_t mesg;

    memset(&mesg, 0, sizeof(queue_mesg_t));
    GENIE_LOG_INFO("led blink done,goto sleep");
    aos_timer_stop(&led.delay_sleep_timer);
    sensor_set_delay_sleep_flag(0);

    mesg.type = QUEUE_MESG_TYPE_POWER;
    mesg.data = POWER_ENTER_QUICK_SLEEP_FLAG;
    queue_send_data(&mesg);
}

static int led_timer_init(void)
{
    int32_t ret = 0;

    aos_timer_new(&led.blink_timer, led_timer_cb, NULL, LED_BLINK_MODE_PROVISONING, 1);
    aos_timer_stop(&led.blink_timer);

    aos_timer_new(&led.delay_sleep_timer, delay_sleep_timer_cb, NULL, LED_BLINK_MODE_DEFAULT_WORKTIME, 0);
    aos_timer_stop(&led.delay_sleep_timer);

    return ret;
}

static int led_timer_set_period(uint32_t peroid_ms)
{
    int ret = 0;

    aos_timer_stop(&led.blink_timer);
    aos_timer_change(&led.blink_timer, peroid_ms);
    aos_timer_start(&led.blink_timer);

    return ret;
}

static void led_gpio_init(void)
{
    led.led_gpio.port = SENSOR_LED_PIN;
    led.led_gpio.config = OUTPUT_PUSH_PULL;

    hal_gpio_init(&led.led_gpio);
}

static int led_blink(uint32_t peroid_ms, uint32_t count)
{
    int ret = 0;

    sensor_set_delay_sleep_flag(1);
    genie_lpm_disable(); //exit low power orelse LED can't work

    led.blink_count = count * 2;
    GENIE_LOG_INFO("led(c:%d)(p:%d)", count, peroid_ms);

    ret = led_timer_set_period(peroid_ms);
    if (ret < 0)
    {
        return -1;
    }

    led_gpio_init();
    sensor_set_led_status(LED_ON);

    aos_timer_stop(&led.delay_sleep_timer);
    aos_timer_change(&led.delay_sleep_timer, led.blink_count * peroid_ms);
    aos_timer_start(&led.delay_sleep_timer);

    return ret;
}

int32_t sensor_led_do_work(led_work_mode_e work_mode)
{
    switch (work_mode)
    {
    case LED_WORK_MODE_PROVISONING:
    {
        led_blink(LED_BLINK_MODE_PROVISONING, PROVISION_LED_BLINK_COUNT);
    }
    break;
    case LED_WORK_MODE_UNPROVISION:
    {
    }
    break;
    case LED_WORK_MODE_PROVISIONED:
    {
        led_blink(LED_BLINK_MODE_PROVISIONED, 3);
    }
    break;

    case LED_WORK_MODE_SINGLE_PRESS:
    case LED_WORK_MODE_DOUBLE_PRESS:
    case LED_WORK_MODE_LONG_PRESS:
    {
    }
    break;
    case LED_WORK_MODE_STANDBY:
    {
        led_blink(LED_BLINK_MODE_STANDBY, 2);
    }
    break;
    case LED_WORK_MODE_LOW_BATTERY:
    {
        led_blink(LED_BLINK_MODE_LOW_BATTERY, 2);
    }
    break;
    case LED_WORK_MODE_OTA:
    {
        led_blink(LED_BLINK_MODE_OTA, 30);
    }
    break;
    default:
    {
        GENIE_LOG_WARN("not support work mode");
    }
        return -1;
    }

    return 0;
}

int32_t sensor_led_init(void)
{
    memset(&led, 0, sizeof(sensor_led_t));

    led_gpio_init();
    led_timer_init();

    return sensor_set_led_status(LED_OFF);
}
